;;; Mudsync --- Live hackable MUD
;;; Copyright © 2016 Christopher Allan Webber <cwebber@dustycloud.org>
;;;
;;; This file is part of Mudsync.
;;;
;;; Mudsync is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; Mudsync is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with Mudsync.  If not, see <http://www.gnu.org/licenses/>.

(define-module (mudsync run-game)
  #:use-module (mudsync game-master)
  #:use-module (8sync)
  #:use-module (8sync repl)
  #:use-module (fibers conditions)
  ;; #:use-module (8sync debug)
  #:use-module (srfi srfi-1)
  #:use-module (ice-9 receive)
  #:use-module (ice-9 q)
  #:use-module (ice-9 match)
  #:export (run-demo
            do-inject-special!
            make-special-injector

            ;; Debug stuff, might go away
            %live-gm %live-hive
            inject-gameobj!))


;;; Debugging stuff
;;; ===============

;; @@: Could these be parameterized and this still work?
(define %live-gm #f)
(define %live-hive #f)

;; Evil!  This uses a global variable... but it's hard to give any more
;; convenient way of providing something for live hacking (which is
;; "quasi-evil for productivity's sake" anyway).  You can set up your own
;; solution which doesn't use a global though.

(define %inject-queue #f)

(define (inject-gameobj! game-spec special-symbol)
  (if %inject-queue
      (let ((gameobj-spec
             (or (find
                  (lambda (entry) (eq? (car entry) special-symbol))
                  game-spec)
                 (throw 'no-such-symbol "Can't find such a symbol in the game-spec"
                        #:symbol special-symbol))))
        (enq! %inject-queue (cons gameobj-spec special-symbol)))
      (display "Game hasn't been started...\n"))
  'done)

(define-actor <gameobj-injector> (<actor>)
  ((repl-update gameobj-injector-inject-queued))
  (gm #:init-keyword #:gm
      #:getter .gm))

(define (gameobj-injector-inject-queued injector message)
  (while (not (q-empty? %inject-queue))
    (match (deq! %inject-queue)
      ((gameobj-spec . special-symbol)
       (<-wait (.gm injector) 'inject-special!
               #:special-symbol special-symbol
               #:gameobj-spec gameobj-spec)))))


;;; Game running stuff
;;; ==================

(define* (run-demo game-spec default-room #:key repl-server)
  (run-hive
   (lambda (hive)
     (define new-conn-handler
       (make-default-room-conn-handler default-room))
     (define gm
       ;; (bootstrap-actor-gimmie* hive <game-master> "gm"
       ;;                          #:new-conn-handler new-conn-handler)
       (create-actor* <game-master> "gm"
                      #:new-conn-handler new-conn-handler))
     (define injector
       (create-actor <gameobj-injector>
                     #:gm gm))

     (define repl-manager
       (create-actor* <repl-manager> "repl"
                      #:subscribers (list injector)))

     ;; (set! %live-gm gm)
     (set! %live-hive hive)

     (set! %inject-queue (make-q))

     (<- gm 'init-world
         #:game-spec game-spec)
     ;; (run-hive hive
     ;;           (list (bootstrap-message hive (actor-id gm) 'init-world
     ;;                                    #:game-spec game-spec)))
     (wait (make-condition)))
   ;; Just for testing / for now...
   #:parallelism 1))
